using System;

namespace Taste {

  public class Obj {
    public string name;    // name of the object
    public int type;       // type of the object (undef for procs)
    public Obj  next;      // to next object in same scope
    public int kind;
    public int adr;        // address in memory or start of proc
    public int level;      // nesting level of declaration
    public Obj locals;     // scopes: to locally declared objects
    public int nextAdr;    // scopes: next free address in this scope
  }

  public class TL {

    // types
    public const int undef = 0;
    public const int integer = 1;
    public const int boolean = 2;

    // object kinds
    public const int vars = 0;
    public const int procs = 1;
    public const int scopes = 2;

    public static int curLevel;  // nesting level of current scope
    public static Obj undefObj;  // object node for erroneous symbols
    public static Obj topScope;  // topmost procedure scope

    public static void EnterScope () {
      Obj scope = new Obj();
      scope.name = ""; scope.type = undef; scope.kind = scopes;
      scope.locals = null; scope.nextAdr = 3;
      scope.next = topScope; topScope = scope;
      curLevel++;
    }

    public static void LeaveScope () {
      topScope = topScope.next; curLevel--;
    }

    public static int DataSpace () {
      return topScope.nextAdr - 3;
    }

    public static Obj NewObj (string name, int kind) {
      Obj p, obj = new Obj();
      obj.name = name; obj.type = undef; obj.kind = kind;
      obj.level = curLevel;
      p = topScope.locals;
      while (p != null) {
        if (p.name == name) Parser.SemError(1);
        p = p.next;
      }
      obj.next = topScope.locals; topScope.locals = obj;
      if (kind == vars) {obj.adr = topScope.nextAdr; topScope.nextAdr++;}
      return obj;
    }

    public static Obj This (string name) {
      Obj obj, scope;
      scope = topScope;
      while (scope != null) {
        obj = scope.locals;
        while (obj != null) {
          if (obj.name == name) return obj;
          obj = obj.next;
        }
        scope = scope.next;
      }
      Parser.SemError(2);
      return undefObj;
    }

    public static void Init () {
      topScope = null; curLevel = 0;
      undefObj = new Obj();
      undefObj.name  =  "undef"; undefObj.type = undef;
      undefObj.kind  = vars; undefObj.adr = 0;
      undefObj.level = 0; undefObj.next = null;
    }

  } // end TL

} // end namespace

